
package com.jf.cloud.delivery.feign;

import com.jf.cloud.api.delivery.dto.CalculateAndGetDeliverInfoDTO;
import com.jf.cloud.api.delivery.dto.ChangeOrderAddrDTO;
import com.jf.cloud.api.delivery.dto.DeliveryOrderDTO;
import com.jf.cloud.api.delivery.feign.DeliveryFeignClient;
import com.jf.cloud.api.delivery.vo.AreaVO;
import com.jf.cloud.api.delivery.vo.DeliveryCompanyExcelVO;
import com.jf.cloud.api.delivery.vo.DeliveryOrderFeignVO;
import com.jf.cloud.api.delivery.vo.ShopTransportVO;
import com.jf.cloud.api.delivery.vo.StationVO;
import com.jf.cloud.api.order.feign.OrderSelfStationFeignClient;
import com.jf.cloud.api.user.feign.UserAddrFeignClient;
import com.jf.cloud.api.user.feign.UserConsigneeFeignClient;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.constant.DeliveryType;
import com.jf.cloud.common.order.dto.DvyTypeDTO;
import com.jf.cloud.common.order.vo.*;
import com.jf.cloud.common.product.constant.SpuMold;
import com.jf.cloud.common.product.constant.SpuType;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.delivery.manager.TransportManager;
import com.jf.cloud.delivery.model.SameCity;
import com.jf.cloud.delivery.service.*;
import com.jf.cloud.delivery.vo.DeliveryCompanyVO;
import com.jf.cloud.delivery.vo.TransfeeVO;
import com.jf.cloud.delivery.vo.TransportVO;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Hidden;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zz
 * @date 2020/12/14
 */
@RestController
@Hidden
public class DeliveryFeignController implements DeliveryFeignClient {
    private final Logger LOGGER = LoggerFactory.getLogger(DeliveryFeignController.class);


    @Autowired
    private UserAddrFeignClient userAddrFeignClient;

    @Autowired
    private UserConsigneeFeignClient userConsigneeFeignClient;

    @Autowired
    private SameCityService sameCityService;

    @Autowired
    private TransportManager transportManager;

    @Autowired
    private TransportService transportService;

    @Autowired
    private DeliveryOrderService deliveryOrderService;

    @Autowired
    private DeliveryCompanyService deliveryCompanyService;

    @Autowired
    private MapperFacade mapperFacade;

    @Autowired
    private StationService stationService;

    @Autowired
    private OrderSelfStationFeignClient orderSelfStationFeignClient;

    private final static long TWO = -2;


    @Override
    public ServerResponseEntity<UserDeliveryInfoVO> calculateAndGetDeliverInfo(CalculateAndGetDeliverInfoDTO param) {
        UserDeliveryInfoVO userDeliveryInfo = new UserDeliveryInfoVO();

        // 如果是自提的话，查询出用户使用的自提用户信息
        if (Objects.equals(param.getDvyTypes().get(0).getDvyType(), DeliveryType.STATION.value())) {
            Map<Long, ShopTransFeeVO> shopIdWithShopTransFee = new HashMap<>(16);
            Map<Long, ShopTransFeeVO> supplierIdWithShopTransFeeMap = new HashMap<>(16);
            Map<Long, ShopTransFeeVO> preSaleTransFeeMap = new HashMap<>(16);
            ShopTransFeeVO shopTransFeeVO = new ShopTransFeeVO();
            shopTransFeeVO.setTransfee(0L);
            shopTransFeeVO.setFreeTransfee(0L);
            shopTransFeeVO.setDeliveryTemplateId(0L);
            shopTransFeeVO.setSupplierId(0L);
            shopIdWithShopTransFee.put(param.getDvyTypes().get(0).getShopId(), shopTransFeeVO);
            userDeliveryInfo.setShopIdWithShopTransFee(shopIdWithShopTransFee);
            userDeliveryInfo.setSupplierIdWithShopTransFeeMap(supplierIdWithShopTransFeeMap);
            userDeliveryInfo.setPreSaleTransFeeMap(preSaleTransFeeMap);

            ServerResponseEntity<UserConsigneeVO> userConsigneeResponse = userConsigneeFeignClient.getUseConsignee();
            LOGGER.info("用户选择自提，获取用户自提信息，userConsigneeResponse:{}", userConsigneeResponse);
            if (!userConsigneeResponse.isSuccess()) {
                LOGGER.error("用户选择自提，获取用户自提信息失败，userConsigneeResponse:{}", userConsigneeResponse);
                return ServerResponseEntity.transform(userConsigneeResponse);
            }
            userDeliveryInfo.setUserConsignee(userConsigneeResponse.getData());
            Long userId = AuthUserContext.get().getUserId();
            List<OrderSelfStationVO> userStationList = orderSelfStationFeignClient.getUserStation(userId).getData();
            userDeliveryInfo.setOrderSelfStation(userStationList);
            userDeliveryInfo.setTotalFreeTransfee(0L);
            return ServerResponseEntity.success(userDeliveryInfo);
        }

        // 如果是物流配送，就获取用户的地址信息

        ServerResponseEntity<UserAddrVO> userAddrResponse = userAddrFeignClient.getUserAddrByAddrId(param.getAddrId());
        if (!userAddrResponse.isSuccess()) {
            LOGGER.error("用户选择物流配送，获取用户地址信息失败，userAddrResponse:{}", userAddrResponse);
            return ServerResponseEntity.transform(userAddrResponse);
        }
        UserAddrVO userAddr = userAddrResponse.getData();
        if (userAddr == null) {
            LOGGER.info("用户选择物流配送，获取用户地址信息为空，userAddrResponse:{}", userAddrResponse);
            userDeliveryInfo.setTotalTransfee(0L);
            userDeliveryInfo.setShopCityStatus(-1);
            return ServerResponseEntity.success(userDeliveryInfo);
        }


        userDeliveryInfo.setUserAddr(userAddr);

        //多个店铺总运费
        long actualTransfee = 0;
        //店铺可配送状态
        List<ShopCityStatusVO> shopCityStatusList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        Map<Long, Integer> dvyTypeMap = param.getDvyTypes().stream().collect(Collectors.toMap(DvyTypeDTO::getShopId, DvyTypeDTO::getDvyType));
        Map<Long, List<ShopCartItemVO>> shopCartItemsMap = param.getShopCartItems().stream().collect(Collectors.groupingBy(ShopCartItemVO::getShopId));
        //同城起送费
        Map<Long, Long> shopStartDeliveryFees = new HashMap<>(Constant.INITIAL_CAPACITY);
        actualTransfee = getActualTransfee(userDeliveryInfo, userAddr, actualTransfee, shopCityStatusList, dvyTypeMap, shopCartItemsMap, shopStartDeliveryFees);
        userDeliveryInfo.setShopCityStatusVOS(shopCityStatusList);
        userDeliveryInfo.setShopStartDeliveryFees(shopStartDeliveryFees);
        actualTransfee = Math.max(actualTransfee, 0);
        userDeliveryInfo.setTotalTransfee(actualTransfee);
        return ServerResponseEntity.success(userDeliveryInfo);
    }

    private long getActualTransfee(UserDeliveryInfoVO userDeliveryInfo, UserAddrVO userAddr, long actualTransfee, List<ShopCityStatusVO> shopCityStatusList, Map<Long, Integer> dvyTypeMap, Map<Long, List<ShopCartItemVO>> shopCartItemsMap, Map<Long, Long> shopStartDeliveryFees) {
        for (Map.Entry<Long, List<ShopCartItemVO>> shopKeyCartItemEntry : shopCartItemsMap.entrySet()) {
            if(!dvyTypeMap.containsKey(shopKeyCartItemEntry.getKey())){
                LOGGER.error("店铺id:{}没有配送方式", shopKeyCartItemEntry.getKey());
                break;
            }
            int dvyType = dvyTypeMap.get(shopKeyCartItemEntry.getKey());
            long transfee = 0L;
            ShopCityStatusVO shopCityStatusVO = new ShopCityStatusVO();
            shopCityStatusVO.setShopId(shopKeyCartItemEntry.getKey());
            shopStartDeliveryFees.put(shopKeyCartItemEntry.getKey(), 0L);
//            shopCityStatusVO.setShopCityStatus(1);
            SameCity sameCity = sameCityService.getSameCityByShopId(shopKeyCartItemEntry.getKey());
            if (Objects.nonNull(sameCity)) {
                shopStartDeliveryFees.put(shopKeyCartItemEntry.getKey(), sameCity.getStartFee());
                shopCityStatusVO.setShopCityStatus(sameCity.getStatus() == 1 ? 1 : -2);
            }else{
                shopCityStatusVO.setShopCityStatus(-2);
            }
            //同城配送运费计算
            if (Objects.equals(dvyType, DeliveryType.SAME_CITY.value())) {
                LOGGER.info("同城配送运费计算，获取同城配送信息：{}", sameCity);
                if (Objects.nonNull(sameCity)) {
                    shopStartDeliveryFees.put(shopKeyCartItemEntry.getKey(), sameCity.getStartFee());
                }
                transfee = sameCityService.calculateTransFee(shopKeyCartItemEntry.getValue(), userAddr, userDeliveryInfo);
                LOGGER.info("同城配送运费计算结果：{}", transfee);
            }
            //快递运费计算
            if (Objects.equals(dvyType, DeliveryType.DELIVERY.value())) {
                // 将所有订单传入处理，计算运费
                transfee = transportManager.calculateTransfee(shopKeyCartItemEntry.getValue(), userAddr, userDeliveryInfo);
                LOGGER.info("快递运费计算结果：{}", transfee);
            }
            // 如果该没有开启同城配送，则不需要判断是否在配送范围
            shopCityStatusVO.setShopCityStatus(transfee >= 0 ? 1 : (int) transfee);
            shopCityStatusList.add(shopCityStatusVO);
            transfee = Math.max(transfee, 0);
            actualTransfee += transfee;
        }
        return actualTransfee;
    }

    @Override
    public ServerResponseEntity<List<DeliveryOrderFeignVO>> getByDeliveryByOrderId(Long orderId) {
        return ServerResponseEntity.success(deliveryOrderService.getByDeliveryByOrderId(orderId));
    }

    @Override
    public ServerResponseEntity<Void> saveDeliveryInfo(DeliveryOrderDTO deliveryOrderDTO) {
        deliveryOrderService.saveDeliveryInfo(deliveryOrderDTO);
        return ServerResponseEntity.success();
    }

    @Override
    public ServerResponseEntity<List<ShopTransportVO>> listTransportByShopId(Long shopId) {
        List<TransportVO> list = transportService.listTransport(shopId);
        return ServerResponseEntity.success(mapperFacade.mapAsList(list, ShopTransportVO.class));
    }

    @Override
    public ServerResponseEntity<List<ShopTransportVO>> listTransportByIds(List<Long> transportIds) {
        List<ShopTransportVO> list = transportService.listTransportByIds(transportIds);
        return ServerResponseEntity.success(list);
    }

    @Override
    public ServerResponseEntity<List<DeliveryCompanyExcelVO>> listDeliveryCompany() {
        List<DeliveryCompanyVO> list = deliveryCompanyService.list();
        return ServerResponseEntity.success(mapperFacade.mapAsList(list, DeliveryCompanyExcelVO.class));
    }

    @Override
    public ServerResponseEntity<Double> getOrderChangeAddrAmount(ChangeOrderAddrDTO param) {
        UserAddrVO userAddr = param.getUserAddrVO();
        double changeAmount;
        Long freightAmount = param.getFreightAmount();
        List<ShopCartItemVO> shopCartItems = param.getShopCartItems();
        long transFee = 0;
        if (Objects.equals(param.getDvyType(), DeliveryType.DELIVERY.value())) {
            // 物流配送
            transFee = transportManager.calculateTransfee(shopCartItems, userAddr, new UserDeliveryInfoVO());
            LOGGER.info("快递配送，快递运费计算结果：{}", transFee);
        } else if (Objects.equals(param.getDvyType(), DeliveryType.SAME_CITY.value())) {
            // 同城配送
            transFee = sameCityService.calculateTransFee(shopCartItems, userAddr, new UserDeliveryInfoVO());
            if (transFee == TWO) {
                throw new LuckException("当前店铺未开启同城配送!");
            } else if (transFee == -1) {
                throw new LuckException("超出当前设置的配送距离!");
            }
        }
        changeAmount = Arith.sub(transFee, freightAmount);
        return ServerResponseEntity.success(changeAmount);
    }

    @Override
    public ServerResponseEntity<List<DeliveryOrderFeignVO>> listDeliveryCountByOrderIds(List<Long> orderIds) {
        List<DeliveryOrderFeignVO> orderFeignVOList = deliveryOrderService.listDeliveryCountByOrderId(orderIds);
        return ServerResponseEntity.success(orderFeignVOList);
    }

    @Override
    public ServerResponseEntity<Boolean> checkAddr(Long deliveryTemplateId, Long userId, Long addrId) {
        if (deliveryTemplateId == null || addrId == null) {
            LOGGER.info("模板id或地址id为空，不校验");
            return ServerResponseEntity.success(false);
        }
        TransportVO transportVO = transportService.getTransportAndAllItemsById(deliveryTemplateId);
        return ServerResponseEntity.success(deliveryOrderService.checkAddr(transportVO, userId, addrId));
    }

    @Override
    public ServerResponseEntity<Boolean> checkDeliveryRange(Long deliveryTemplateId, Long addrId) {
        if (deliveryTemplateId == null || addrId == null) {
            return ServerResponseEntity.success(false);
        }
        // 查询用户地址
        UserAddrVO addrVO = userAddrFeignClient.getUserAddrByAddrId(addrId).getData();
        if (addrVO == null) {
            return ServerResponseEntity.success(false);
        }
        // 取出区域id，优先 区id -> 市id -> 省id
        Long areaId;
        if (addrVO.getAreaId() != null) {
            areaId = addrVO.getAreaId();
        } else if (addrVO.getCityId() != null) {
            areaId = addrVO.getCityId();
        } else if (addrVO.getProvinceId() != null) {
            areaId = addrVO.getProvinceId();
        } else {
            return ServerResponseEntity.success(false);
        }
        // 查询配送模板，并初步校验
        TransportVO transportVO = transportService.getTransportAndAllItemsById(deliveryTemplateId);
        if (transportVO == null || transportVO.getTransFees() == null) {
            return ServerResponseEntity.success(false);
        }
        if (transportVO.getIsFreeFee() == 1) {
            return ServerResponseEntity.success(true);
        }
        // 获取可配送的区域id集合
        List<AreaVO> areaList = new ArrayList<>();
        for (TransfeeVO transFee : transportVO.getTransFees()) {
            areaList.addAll(transFee.getCityList());
        }
        Set<Long> areaIds = areaList.stream().map(AreaVO::getAreaId).collect(Collectors.toSet());
        // 校验数据
        if (areaIds.contains(areaId)) {
            return ServerResponseEntity.success(true);
        }
        return ServerResponseEntity.success(false);
    }

    @Override
    public ServerResponseEntity<StationVO> getStationInfoById(Long stationId){
        StationVO stationVO = stationService.getByStationId(stationId);
        return ServerResponseEntity.success(stationVO);
    }

}
